﻿using System;
using System.Collections.Generic;
using System.Linq;

using System.Security.Cryptography;
using System.Net.Sockets;

using NetworkManagement;

namespace LorraineSec.ServerApplication
{
    /// <summary>
    /// The base class for a Application Server
    /// </summary>
    public class Server
    {
        /// <summary>
        /// The delegate for subscribing to the server's output.
        /// </summary>
        /// <param name="output">The output string from the server.</param>
        public delegate void ServerOutputCallback(OutputFlag flag, string output);

        public enum OutputFlag { TEXT,UPDATE };

        /// <summary>
        /// An enumeration of the server's possible states.
        /// </summary>
        public enum Status
        {
            /// <summary>
            /// The server is currently idling waiting to be started.
            /// </summary>
            IDLE,
            /// <summary>
            /// The server is in the process of starting up.
            /// </summary>
            STARTING,
            /// <summary>
            /// The server is current executing.
            /// </summary>
            RUNNING,
            /// <summary>
            /// The server is in the processing of shutting down.
            /// </summary>
            STOPPING
        }

        /// <summary>
        /// The current state of the server.
        /// </summary>
        public Status serverStatus { get; protected set; }

        /// <summary>
        /// The random number generator for the server.
        /// </summary>
        protected Random rng;
        /// <summary>
        /// The PublicKey cryptographic service for the server.
        /// </summary>
        protected RSACryptoServiceProvider PublicKey;

        private ServerOutputCallback subscriber;

        /// <summary>
        /// Constructs a server object
        /// </summary>
        /// <param name="callback">The output callback delegate.</param>
        public Server(ServerOutputCallback callback)
        {
            subscriber = callback;

            PublicKey = new RSACryptoServiceProvider();
            rng = new Random((int)DateTime.UtcNow.Ticks);

            serverStatus = Status.IDLE;
        }

        /// <summary>
        /// Initializes the Server
        /// </summary>
        /// <returns>True is successful. False if unsuccessful.</returns>
        public virtual bool init() { return false; }

        /// <summary>
        /// Starts the Server
        /// </summary>
        /// <returns>True is successful. False if unsuccessful.</returns>
        public virtual bool start() { return false; }

        /// <summary>
        /// Stops the Server
        /// </summary>
        /// <returns>True is successful. False if unsuccessful.</returns>
        public virtual bool stop() { return false; }

        /// <summary>
        /// Called by the server to relay output to the server's subscriber.
        /// </summary>
        /// <param name="txt">The output string from the server.</param>
        protected void output(OutputFlag flag, string txt)
        {
            subscriber.BeginInvoke(flag, txt, null, null);
        }

        /// <summary>
        /// Properly disconnects a socket, making sure the socket is 
        /// actually connected to avoid exceptions.
        /// </summary>
        /// <param name="sock"></param>
        protected void disconnectSocket(Socket sock)
        {
            if (sock != null && sock.Connected)
            {
                sock.Shutdown(SocketShutdown.Both);
                sock.Close();
            }
        }
    }
}
